# -*- coding: utf-8 -*-
# @author: chenhuachao
# @time: 2018/7/2
# desc :常用工具集合
import re
from functools import wraps
import pymysql.cursors
from django.http import QueryDict, JsonResponse
from django.shortcuts import redirect
from shujuyuan.models import TdsdDataSource
import uuid
import ftplib
import cx_Oracle
from yonghuguanli.models import TdsdUser, TdsdApplyResource, UserApi
from ziyuanguanli.models import TdsdResourceList

class MysqlOperate(object):
    def __init__(self):
        self.conn = ""


def user_login(center_fun):
    """验证用户是否登录的装饰器"""

    @wraps(center_fun)
    def fun(request, *args, **kwargs):
        # if request.session.has_key('user_id'):  # pep8弃用
        # TODO 一般情况下以下三行不需要，目的是确保删除已登录的用户后，已经登录的用户不能再进行操作了
        user = TdsdUser.objects.filter(id=request.session.get('user_id'), isdelete=0).first()
        if not user:
            request.session.delete(session_key=request.session.session_key)
            return redirect('/user/login/')
        if 'user_id' in request.session:
            return center_fun(request, *args, **kwargs)
        else:
            # 点击退出的情况，无需return_url
            if 'logout' in request.path:
                return redirect('/user/login/')  # 没有return_url的情况下，登录后进入用户中心基本资料页面
            # return_url是登录成功后，返回的页面url
            else:
                return redirect('/user/login/?return_url=%s' % request.path)

    return fun


def api_verification(center_fun):
    """验证用户使用api时，参数携带是否正确"""

    @wraps(center_fun)
    def fun(request, resource_id, *args, **kwargs):
        # 验证此资源是公开的还是需要申请的，以及资源是否还存在
        trl_obj = TdsdResourceList.objects.filter(resource_id=resource_id, status=0).first()
        if trl_obj:
            username = request.GET.get('username')
            token = request.GET.get('token')
            appkey = request.GET.get('appkey')
            status = trl_obj.resource_status
            if status == 0:  # 需授权，验证user_id,resource_id,token
                user = TdsdUser.objects.filter(username=username, isdelete=0).first()
                user_id = user.id if user else None
                print(user_id, resource_id, token)
                tar_obj = TdsdApplyResource.objects.filter(apply_user_id=user_id, resource_id=resource_id,
                                                           token=token, status=1).first()
                if tar_obj:
                    return center_fun(request, resource_id, *args, **kwargs)
                else:
                    return JsonResponse({'code': 1, 'msg': '参数错误'})
            else:  # 无需授权，直接验证用户是否存在即可，如果有多余参数，不管他即可
                # 通过用户名和appkey来确定用户是否有冒用他人名称调用api
                user = TdsdUser.objects.filter(username=username, appkey=appkey, isdelete=0).first()
                if user:
                    return center_fun(request, resource_id, *args, **kwargs)
                else:
                    return JsonResponse({'code': 1, 'msg': '参数错误'})
        else:
            return JsonResponse({'code': 1, 'msg': '资源不存在'})

    return fun


def request_body_serialize(request):
    """
    对request.body做QuertDict编码转换处理
    如果不做数据处理：格式b‘id=49&name=%E4%B8%AD&name_cn=&comment=‘
    页面中提交的中文“中”，变成%E4%B8%AD
    :param request:
    :return:
    """
    querydict = QueryDict(request.body.decode("utf-8"), encoding="utf-8")
    response_dict = {}
    try:
        for key, val in querydict.items():
            response_dict[key] = val
    except:
        pass
    return response_dict


def getDbinfoByDbId(dbinfo, columsstr, tablename, start, end):
    '''
    根据数据库id获取表信息
    :param dbinfo: 数据库连接信息
    :param sqltype:  sql类型；oracle-mysql
    :param columsstr: 需要查询的字段。string
    :param tablename: 表名称
    :param start: 分页大小。
    :return:
    '''
    tabledata_10 = []

    if dbinfo.db_cate == "MySQL":
        conn_dict = {
            "host": dbinfo.host_ip,
            "user": dbinfo.username,
            "password": dbinfo.password,
            "db": dbinfo.sid,
            "charset": "utf8",
            "cursorclass": pymysql.cursors.DictCursor

        }
        conn = pymysql.connect(**conn_dict)
        with conn.cursor() as cursor:
            sql = f"select {columsstr} from {tablename} limit {start},1000"
            print(sql)
            cursor.execute(sql)
            tabledata_10 = cursor.fetchall()
    elif dbinfo.db_cate == "Oracle":
        oracleUrl = '{user}/{passwd}@{ip}/{db}'.format(user=dbinfo.username, passwd=dbinfo.password,
                                                       ip=dbinfo.host_ip, db=dbinfo.sid)
        conn = cx_Oracle.connect(oracleUrl)
        with conn.cursor() as cursor:
            sql = f"select {columns} from {tablename} where rownum BETWEEN  {start} and {end}"
            cursor.execute(sql)
            tabledata_10 = cursor.fetchall()
    return tabledata_10


def compress_UUID():
    '''
    根据http://www.ietf.org/rfc/rfc1738.txt,由uuid编码扩大字符域生成串
    包括: [0-9a-zA-Z\-_] 共64个
    长度: (32-2)/3*2 = 20
    备注: 可在地球上人人都用,使用100年不重复(2^120)
    :return:String
    '''
    SAFEHASH = [x for x in "0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
    row = str(uuid.uuid4()).replace('-', '')
    safe_code = ''
    for i in range(10):
        enbin = "%012d" % int(bin(int(row[i * 3] + row[i * 3 + 1] + row[i * 3 + 2], 16))[2:], 10)
        safe_code += (SAFEHASH[int(enbin[0:6], 2)] + SAFEHASH[int(enbin[6:12], 2)])
    return safe_code


def record_api_use(request, create_id, resource_status):
    '''
    添加api请求记录
    :param request:
    :param create_id: 资源的创建者的id
    :param resource_status: 资源的状态
    :return:
    '''
    user_id = TdsdUser.objects.values('id').get(username=request.GET.get('username')).get('id')
    # api = request.path # 获取不带参数的url
    fuwu = request.get_host()  # 获取服务器ip
    # /resource/api/5/?username=heyin&appkey=4a72acf5c81046c6a037e185e83cc102
    api = str(fuwu) + str(request.get_full_path())  # 获取带参数的url
    key = re.search(r'appkey|token',api).group()
    # 隐藏用户的隐私数据token或appkey
    api = re.sub(r'appkey=[^&' ']*|token=[^&' ']*',''+key+'=***',api)
    try:  # 获取客户端ip地址
        real_ip = request.META['HTTP_X_FORWARDED_FOR']
        ip = real_ip.split(",")[0]
    except:
        try:
            ip = request.META['REMOTE_ADDR']
        except:
            ip = ""
    user_api_obj = UserApi.objects.create(
        user_id=user_id,
        create_id=create_id,
        api=api,
        user_ip=ip,
        resouce_status=resource_status
    )
    user_api_obj.save()


class FormVerify(object):
    """对前端form表单发送来的各项数据进行格式的单独验证"""
    instance = None

    def __new__(cls, *args, **kwargs):  # 单例
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    @staticmethod
    def verify_username(username):
        ret = re.match(r'^[a-zA-Z\u4e00-\u9fa5][a-zA-Z0-9\u4e00-\u9fa5]{4,59}$', username)
        return True if ret else False

    @staticmethod
    def verify_password(password):
        ret = re.match(r'^[\S]{6,15}$', password)
        return True if ret else False

    @staticmethod
    def verify_telephone(telephone):
        if telephone == '':  # 手机号可以为空字符串，但是如果不是空字符串，就要验证格式是否正确
            return True
        ret = re.match(r'^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$', telephone)
        return True if ret else False

    @staticmethod
    def verify_source_name(source_name):
        ret = re.match(r'^[a-zA-Z\u4e00-\u9fa5_][a-zA-Z0-9\u4e00-\u9fa5_]+$', source_name)
        return True if ret else False

    @staticmethod
    def verify_ip(*args):
        p = re.compile(r'((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)')
        for ip in args:
            ret = p.match(ip)
            if not ret:
                break
            # ret = re.match(r'((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)', ip)
        else:
            return True
        return False

    @staticmethod
    def verify_port(port):
        ret = re.match(r'^\d{1,6}$', port)
        return True if ret else False





def ftp_upload(username,password,host,fileByte,filename):
    '''
    ftp上传功能
    :param username:
    :param password:
    :param host:
    :param fileByte:
    :param filename:
    :return:
    '''
    print(">>>>>",username,password,host,fileByte,filename)
    try:
        f=ftplib.FTP(host)
        f.encoding='utf-8'
        f.login(username,password)
        bufsize=1024
        f.storbinary('STOR ' + filename, fileByte, bufsize)
        f.close()
        error=""
        fileurl="ftp://{host}/{filename}".format(host=host,filename=filename)
        return True, error,fileurl
    except Exception as e:
        error=str(e)
        return False,error,""


def ftp_download(username,password,host,localpath,remotepath):
    '''
    ftp下载功能
    :return:
    '''
    try:
        bufsize = 1024
        f=ftplib.FTP(host)
        f.login(username,password)
        fp = open(localpath, 'wb')
        f.retrbinary('RETR ' + remotepath, fp.write, bufsize)
        f.set_debuglevel(0)
        fp.close()
        f.close()
    except Exception as e:
        import traceback
        traceback.print_exc()
        return False,str(e)
